home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac 1993 September
/
clonecd
/
September 93.img
/
Archives
/
Fun, Tricks & Hacks
/
Silent Alarm, not!
/
SonicAlarmMisc.c
< prev
next >
Wrap
Text File
|
1992-06-15
|
18KB
|
699 lines
#ifdef THINK_C
#include <MacHeaders>
#else
#pragma load "MPWHeaders"
#endif
#include <StdDef.h>
#include <Palettes.h>
#ifndef __SONICALARM__
#include "SonicAlarm.h"
#endif
#ifndef __SONICALARMMISC__
#include "SonicAlarmMisc.h"
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// globals used for sound routines
// gSndInputRef is the sound input device's reference number
long gSndInputRef;
// gSndChanPtr is a sound channel for playing sounds, duh
SndChannelPtr gSndChanPtr;
// snd resource handle of our sound
Handle gSndHandle;
// handle state of last snd resource
char gOldState;
// handle used for averaging volume levels
short **gLevelsArray;
// this is the index of the next volume level to record
short gLevelIndex;
// percentage represented as a Fixed point number
Fixed gSensitivity;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// private prototypes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// determine if the machine has a sound input driver running
Boolean HasSoundInput(void)
{
long gestaltResult;
OSErr err;
err = Gestalt(gestaltSoundAttr, &gestaltResult);
FailIf(err != noErr, GestaltErr);
return ( (gestaltResult >> gestaltHasSoundInputDevice) & 1 );
GestaltErr:
return (false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSErr InitSndTools(void)
{
OSErr err;
short meterOn;
gSndInputRef = 0;
gSndChanPtr = nil;
err = SndNewChannel(&gSndChanPtr, sampledSynth, 0, nil);
FailIf(err != noErr, ChanErr);
err = SPBOpenDevice(nil, siWritePermission, &gSndInputRef);
FailIf(err != noErr, SndInErr);
meterOn = 1;
err = SPBSetDeviceInfo(gSndInputRef, siLevelMeterOnOff, (Ptr)&meterOn);
FailIf(err != noErr, SndInErr);
return (noErr);
SndInErr:
SndDisposeChannel(gSndChanPtr, true);
ChanErr:
return (err);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CloseSndTools(void)
{
CloseSndChan();
CloseSndDevice();
if (gSndHandle != nil)
DisposHandle(gSndHandle);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CloseSndDevice(void)
{
OSErr err;
if (gSndInputRef != 0) {
err = SPBCloseDevice(gSndInputRef);
FailIf(err != noErr, SndErr);
}
SndErr:
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// find the sound header inside of the given snd handle
OSErr GetBufferOffset(Handle sndHandle, long *offset)
{
short howManyCmds;
Ptr cruisePtr;
OSErr result;
FailIf(sndHandle == nil, BadHandle);
FailIf(*sndHandle == nil, BadHandle);
result = noErr;
*offset = 0;
// set the pointer past the first two words of the snd
// this is correct for both format 1 and 2 resources
cruisePtr = *sndHandle + offsetof(SndListResource, modifierPart);
// if it's a format 1, then point past the modifier parts
if ( ((SndListPtr)*sndHandle)->format == firstSoundFormat )
cruisePtr += sizeof(ModRef) * ((SndListPtr)*sndHandle)->numModifiers;
// now pointing at number of cmds
howManyCmds = *((short *)cruisePtr);
cruisePtr += sizeof(howManyCmds);
// cruisePtr is now at the first sound command
// cruise all commands and find a soundCmd or bufferCmd
do {
switch (((SndCmdPtr)cruisePtr)->cmd) {
case (soundCmd | dataOffsetFlag):
case (bufferCmd | dataOffsetFlag):
*offset = ((SndCmdPtr)cruisePtr)->param2;
howManyCmds = 0; // done, get out of loop
break;
default: // catch any other type of cmd
cruisePtr += sizeof(SndCommand);
howManyCmds -= 1;
break;
}
} while (howManyCmds >= 1); // done with all the commands
FailWithAction(*offset == 0, result = badFormat, Failure);
return(result);
BadHandle:
result = nilHandleErr;
Failure:
return(result);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Boolean IsPlayingSound(void)
{
SCStatus theStatus;
OSErr err;
err = SndChannelStatus(gSndChanPtr, sizeof(theStatus), &theStatus);
if (err == noErr)
return (theStatus.scChannelBusy);
else
return (false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSErr PlaySound(short resID)
{
SndCommand theCmd;
long offset;
OSErr err;
StopPlaying();
gSndHandle = GetResource('snd ', resID);
FailIf(gSndHandle == nil, NoHandle)
gOldState = HGetState(gSndHandle);
HNoPurge(gSndHandle);
HLock(gSndHandle);
err = GetBufferOffset(gSndHandle, &offset);
FailIf(err != noErr, NoHandle)
theCmd.cmd = bufferCmd;
theCmd.param1 = 0;
theCmd.param2 = (long) *gSndHandle + offset;
err = SndDoCommand(gSndChanPtr, &theCmd, true);
FailIf(err != noErr, CmdErr)
return (noErr);
CmdErr:
HSetState(gSndHandle, gOldState);
NoHandle:
return (err);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void StopPlaying(void)
{
OSErr err;
SndCommand theCmd;
theCmd.cmd = flushCmd;
err = SndDoImmediate(gSndChanPtr, &theCmd);
FailIf(err != noErr, CmdErr)
theCmd.cmd = quietCmd;
err = SndDoImmediate(gSndChanPtr, &theCmd);
FailIf(err != noErr, CmdErr)
CmdErr:
HSetState(gSndHandle, gOldState);
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CloseSndChan(void)
{
OSErr err;
err = SndDisposeChannel(gSndChanPtr, true);
FailIf(err != noErr, ChanErr);
gSndChanPtr = nil;
ChanErr:
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
short GetCurLevel(void)
{
OSErr err;
short meterData[2];
err = SPBGetDeviceInfo(gSndInputRef, siLevelMeterOnOff, (Ptr) meterData);
FailIf(err != noErr, SndErr);
if (meterData[0]) // level metering on?
return (meterData[1]);
SndErr:
return (0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void DrawCountDown(WindowPtr window, Point location, long *lastTickCount, short *secondsCountDown)
{
Str255 delayStr;
long curTicks;
// are we active and did more than a second pass yet?
curTicks = TickCount();
if (*lastTickCount + kOneSecondTicks < curTicks) {
*lastTickCount = curTicks;
SetPort(window);
TextFont(kActivatingFontID);
TextSize(kActivatingFontSize);
// erase the previous number
ForeColor(whiteColor);
NumToString(*secondsCountDown + 1, delayStr);
MoveTo(location.h - StringWidth(delayStr), location.v);
DrawString(delayStr);
// draw the next number
ForeColor(redColor);
NumToString(*secondsCountDown, delayStr);
MoveTo(location.h - StringWidth(delayStr), location.v);
DrawString(delayStr);
// restore the foreground color
ForeColor(blackColor);
(*secondsCountDown)--;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// draw dots on the screen for each char in password
void DrawPassword(Rect drawArea, short length)
{
FontInfo info;
short i;
TextFont(systemFont);
TextSize(kSystemFontSize);
GetFontInfo(&info);
MoveTo(drawArea.left + kEditTextInset,
drawArea.bottom - info.descent - kEditTextInset);
InsetRect(&drawArea, kEditTextInset, kEditTextInset);
EraseRect(&drawArea);
for (i = length - 1; i >= 0; --i)
DrawChar((short)charBullet);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Boolean IsVolumeTooLoud(void)
{
Fixed percentage;
if (IsPlayingSound())
return (false);
else {
percentage = (GetCurLevel() << 16) / GetAverageLevel();
if (percentage < ((kMimimumSensivity << 16) / 100))
percentage = ((kMimimumSensivity << 16) / 100);
}
return (percentage > gSensitivity);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
short GetAverageLevel(void)
{
short i;
long result;
short *nextLevel;
result = 0;
nextLevel = *gLevelsArray;
for (i = kNumberOfLevels - 1; i >=0; --i)
result += *nextLevel++;
return (result >> kNumLevelsShift);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void UpdateAverageLevel(void)
{
if ( !IsPlayingSound() ) {
if ( gLevelIndex > (kNumberOfLevels - 1) )
gLevelIndex = 0;
(*gLevelsArray)[gLevelIndex++] = GetCurLevel();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pass in a percentage number (i.e. 10% is the number 10)
void SetSensitivity(short percentage)
{
gSensitivity = (percentage << 16) / 100;
gSensitivity += kFixed100Percent;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// returns a percentage number (i.e. 10% is the number 10)
short GetSensitivity(void)
{
Fixed result;
result = (gSensitivity - kFixed100Percent) * 100;
// if greator that xx.5 then add 1
if ((result & 0x0000FFFF) > 0x00008000)
result += 0x00010000;
return (result >> 16);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// InitGraf is always implemented (trap 0xA86E). If the trap table is big
// enough, trap 0xAA6E will always point to either Unimplemented or some other
// trap, but will never be the same as InitGraf. Thus, you can check the size
// of the trap table by asking if the address of trap 0xA86E is the same as 0xAA6E.
short NumToolboxTraps(void)
{
if ( GetToolboxTrapAddress(_InitGraf) == GetToolboxTrapAddress(0xAA6E) )
return (0x0200);
else
return (0x0400);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check to see if a given trap is implemented. GetTrapAddress may fuck up and
// wrap around into the trap table if you give it a toolbox trap that is out of
// range, so check for this first.
Boolean TrapExists(short theTrap)
{
long trapAddress;
if ( IsBitsAreClear(theTrap, kOSTrapBit) )
trapAddress = GetOSTrapAddress(theTrap);
else {
ClearBits(kATrapBits, theTrap); // get the trap number
if ( theTrap < NumToolboxTraps() ) // can this tool trap exist?
trapAddress = GetToolTrapAddress(theTrap);
else
return (false);
}
return ( GetToolboxTrapAddress(_Unimplemented) != trapAddress );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Boolean FailLowMemory(long memRequested)
{
long total;
long contig;
PurgeSpace(&total, &contig);
return (total < (memRequested + kMinHeap));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void AlertUser(short errNum, short errStrIndex, Boolean fatal)
{
short itemHit;
Str255 msg1;
Str255 msg2;
if (errNum != userCanceledErr) { // ignore cancels
SetCursor(&qd.arrow);
if (errNum)
NumToString(errNum, msg1);
else
msg1[0] = 0; // empty string
GetIndString(msg2, kErrStrings, errStrIndex);
ParamText(msg1, msg2, "\p", "\p");
itemHit = Alert(rUserAlert, nil);
if (fatal)
ExitToShell();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSErr CreateLevelArray(void)
{
OSErr result;
result = noErr;
gLevelIndex = 0;
FailWithAction(FailLowMemory(kNumberOfLevels * sizeof(short)), result = MemError(), NoArray);
gLevelsArray = (short **)NewHandleClear(kNumberOfLevels * sizeof(short));
FailWithAction(gLevelsArray == nil, result = MemError(), NoArray);
NoArray:
return (result);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// limit the Pascal string to the max, and return the new length
// there's a Pascal length byte, so subtract one too (three four)
unsigned char LimitStringLength(StringPtr pString, unsigned char max)
{
short length;
length = Length(pString);
if (length > (max - 1))
length = 0;
length++;
*pString = length;
return (length);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check to see if a window belongs to a desk accessory.
Boolean IsDAWindow(WindowPtr window)
{
if (window == nil)
return false;
else // DA windows have negative windowKinds
return ((WindowPeek) window)->windowKind < 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Given the button control handle, this will cause the button to look as
// if it has been clicked in. This is nice to do for the user if they type
// return or enter to select the default item.
void SelectButton(ControlHandle button)
{
long finalTicks;
HiliteControl(button, kSelect);
Delay(kVisualDelay, &finalTicks);
HiliteControl(button, kDeselect);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void* GetMyWindow(long windowSize, short windID)
{
Ptr window;
long response;
OSErr err;
Boolean hasColor;
err = Gestalt(gestaltQuickdrawFeatures, &response);
hasColor = (err == noErr) && (response & (1 << gestaltHasColor));
window = NewPtrClear(windowSize);
FailIf(window == nil, NoPtr)
if (hasColor)
window = (Ptr)GetNewCWindow(windID, window, (WindowPtr)-1);
else
window = (Ptr)GetNewWindow(windID, window, (WindowPtr)-1);
FailIf(window == nil, NoWindow)
SetPort((WindowPtr)window);
SetWRefCon((WindowPtr)window, windID);
return (window);
NoWindow:
DisposePtr(window);
NoPtr:
return (nil);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// make sure there's a window pointer and get it's type from the refCon
long GetMyWindowType(WindowPtr window)
{
long result;
result = 0;
if (window != nil)
result = GetWRefCon(window);
return (result);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Boolean IsWindowModal(WindowPtr window)
{
Boolean result;
short variant;
result = false;
if (window != nil) {
variant = GetWVariant(window);
result = (variant == dBoxProc) || (variant == movableDBoxProc);
}
return (result);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void* FindMyWindow(short windRefCon)
{
WindowPtr window;
window = FrontWindow();
while (window != nil) {
if (GetWRefCon(window) != windRefCon)
window = (WindowPtr)((WindowPeek)window)->nextWindow;
else
break;
}
return (window);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ControlHandle GetMyControl(short cntlRefCon, WindowPtr window)
{
ControlHandle cntlHandle;
cntlHandle = GetNewControl(cntlRefCon, window);
if (cntlHandle != nil)
SetCRefCon(cntlHandle, cntlRefCon);
return (cntlHandle);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ControlHandle FindMyControl(WindowPtr window, short cntlRefCon)
{
ControlHandle cntlHandle;
cntlHandle = ((WindowPeek)(window))->controlList;
while (cntlHandle != nil) {
if (GetCRefCon(cntlHandle) != cntlRefCon)
cntlHandle = (**cntlHandle).nextControl;
else
break;
}
return (cntlHandle);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActivateControls(WindowPtr window, Boolean becomingActive)
{
ControlHandle cntlHandle;
cntlHandle = ((WindowPeek)(window))->controlList;
while (cntlHandle != nil) {
HiliteControl(cntlHandle, becomingActive ? kCntlActivate : kCntlDeactivate);
cntlHandle = (**cntlHandle).nextControl;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// this is a DeviceLoopDrawingProcPtr, which is an easy way to find the target GDevice
pascal void OutlineControl(short depth, short deviceFlags, GDHandle targetDevice, ControlHandle button)
{
#pragma unused (depth, deviceFlags)
WindowPtr oldPort;
Rect theRect;
PenState curPen;
RGBColor backColor;
RGBColor foreColor;
RGBColor grayColor;
short buttonOval;
Boolean isColor;
if (button != nil) {
GetPort(&oldPort);
SetPort((*button)->contrlOwner);
GetPenState(&curPen);
PenNormal();
theRect = (*button)->contrlRect;
InsetRect(&theRect, kButtonFrameInset, kButtonFrameInset);
buttonOval = (theRect.bottom - theRect.top) / 2 + 2;
// check for a color window
if (((CGrafPtr)(*button)->contrlOwner)->portVersion & kIsColorPort)
isColor = true;
else
isColor = false;
if (isColor) {
GetBackColor(&backColor);
GetForeColor(&foreColor);
grayColor = foreColor;
}
if ((**button).contrlHilite == kCntlDeactivate) {
// find a nice gray for color windows, otherwise use a gray pattern
if ((isColor) && GetGray(targetDevice, &backColor, &grayColor))
RGBForeColor(&grayColor);
else
PenPat((ConstPatternParam)&qd.gray);
}
PenSize(kButtonFrameSize, kButtonFrameSize);
FrameRoundRect(&theRect, buttonOval, buttonOval);
if (isColor)
RGBForeColor(&foreColor);
SetPenState(&curPen);
SetPort(oldPort);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Find the greatest overlap device for the given global rectangle.
GDHandle GetRectDevice(Rect globalRect)
{
long area, maxArea;
GDHandle device, deviceToReturn;
Rect intersection;
deviceToReturn = GetMainDevice(); /* Use as default choice. */
maxArea = 0;
for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
if (TestDeviceAttribute(device, screenDevice)
&& TestDeviceAttribute(device, screenActive)
&& SectRect(&globalRect, &((*device)->gdRect), &intersection)) {
area = ((long)(intersection.right - intersection.left)) *
((long)(intersection.bottom - intersection.top));
if (area > maxArea) {
deviceToReturn = device;
maxArea = area;
}
}
}
return(deviceToReturn);
}